/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-09-10 15:53:38
 * @LastEditors: zhl
 * @LastEditTime: 2021-09-30 11:49:21
 * @Description: 文件实现描述
 */
#include "GET-Request.h"
#include <string.h>
#include "hex.h"
#include "MappingDataManager.h"
#include "modbus_datastruct.h"
#include "CLogger.h"
#include <algorithm> 
#include "common.h"


GETRequest GETRequest::c_instance;

GETRequest::GETRequest(/* args */){
    c_piid.fields.sn = 0;
    c_piid.fields.reserve = 0;
    c_piid.fields.priority = 0;
}

GETRequest::~GETRequest(){

}

GETRequest& GETRequest::getInstance(){
    return c_instance;
}

PIID GETRequest::get_piid(){
    std::lock_guard<std::mutex> lock(c_piid_mutex);
    c_piid.fields.sn= 0;
    if(c_piid.fields.sn > 63){
        c_piid.fields.sn = 0;
    }
    return c_piid;
}

int GETRequest::get_modbus_mapping_data_type(MAPPING_POINT_DATA_TYPE& mapping_data){
    switch (mapping_data.data_type)
    {
    case DATA_TYPE_SHORT:
        return 16;
        break;
    case DATA_TYPE_UNSIGNED_SHORT:
        return 18;
        break;
    case DATA_TYPE_INT:
        return 5;
        break;
    case DATA_TYPE_UNSIGNED_INT:
        return 6;
        break;
    case DATA_TYPE_FLOAT:
        return 23;
        break;
    case DATA_TYPE_BIT:
        return 3;
        break;
    case DATA_TYPE_BITS:
        return 4;
        break;
    default:
        break;
    }
    return 0;
}
int GETRequest::get_base_data_type(MAPPING_POINT_DATA_TYPE& mapping_data){
    switch (mapping_data.protocol_type){
    case 1:
        return get_modbus_mapping_data_type(mapping_data);
        break;
    default:
        break;
    }
    return 0;
}
// DLT698_MAPPING_DATA_TYPE GETRequest::get_base_data_type(int code){
//     if(g_dlt698_config.expired()){
//         return DLT698_DATA_TYPE_UNKNOWN;
//     }
//     CLogger::getInstance()->log_w("========================get_base_data_type 1 code = %d", code);
//     std::unordered_map<int64_t, DLT698_DATA_TYPE>::iterator it = g_dlt698_config.lock()->get_dlt698_data_type()->find(code);
//     if(it == g_dlt698_config.lock()->get_dlt698_data_type()->end()){
//         return DLT698_DATA_TYPE_UNKNOWN;
//     }
//     std::string dt = "";
//     dt.resize(32);
//     transform(it->second.data_type.begin(), it->second.data_type.end(), dt.begin(), ::toupper);
//     CLogger::getInstance()->log_e("dlt698 base data type is %s\n", dt.c_str());
//     if((0 == strcmp(dt.c_str(), "BASE")) || (0 == it->second.equal_system_data_type)){
//         std::string strLower = "";
//         strLower.resize(it->second.name.size());
//         transform(it->second.name.begin(), it->second.name.end(), strLower.begin(), ::tolower);
//         CLogger::getInstance()->log_e("dlt698 data type is %s\n", strLower.c_str());
//         if(0 == strLower.compare((const char *)"char")){
//             return DLT698_DATA_TYPE_INT8;
//         } else if((0 == strLower.compare((const char *)"unsigned char")) || 
//                   (0 == strLower.compare((const char *)"uint8_t"))){
//             return DLT698_DATA_TYPE_UINT8;
//         } else if((0 == strLower.compare((const char *)"short"))){
//             return DLT698_DATA_TYPE_INT16;
//         } else if((0 == strLower.compare((const char *)"unsigned short")) || 
//                   (0 == strLower.compare((const char *)"uint16_t"))){
//             return DLT698_DATA_TYPE_UINT16;
//         } else if((0 == strLower.compare((const char *)"int")) || (0 == strLower.compare((const char *)"integer"))){
//             return DLT698_DATA_TYPE_INT32;
//         } else if((0 == strLower.compare((const char *)"uint32_t")) || (0 == strLower.compare((const char *)"unsigned int"))){
//             return DLT698_DATA_TYPE_UINT32;
//         } else if((0 == strLower.compare((const char *)"long"))){
//             return DLT698_DATA_TYPE_LONG;
//         } else if((0 == strLower.compare((const char *)"unsigned long"))){
//             return DLT698_DATA_TYPE_ULONG;
//         } else if((0 == strLower.compare((const char *)"long long"))){
//             return DLT698_DATA_TYPE_INT64;
//         } else if((0 == strLower.compare((const char *)"unsigned long long")) || 
//                   (0 == strLower.compare((const char *)"uint64_t"))){
//            return DLT698_DATA_TYPE_UINT64;
//         } else if((0 == strLower.compare((const char *)"float"))){
//             return DLT698_DATA_TYPE_FLOAT;
//         } else if((0 == strLower.compare((const char *)"double"))){
//             return DLT698_DATA_TYPE_DOUBLE;
//         } else if((0 == strLower.compare((const char *)"string"))){
//             return DLT698_DATA_TYPE_STRING;
//         } else {
//            return DLT698_DATA_TYPE_UNKNOWN;
//         }
//     } else {
//         get_base_data_type(it->second.equal_system_data_type);
//     }

//     return DLT698_DATA_TYPE_UNKNOWN;
// }
int GETRequest::fill_data(int data_type, DLT698_BUFFER& data, std::string value){
    switch(data_type){
        case 3:
        case 15:
            *(char *)(data.data+data.len) = (char)std::stoi(value);
            data.len += sizeof(char);
        break;
        case 17:
            *(uint8_t *)(data.data+data.len) = (uint8_t)std::stoi(value);
            data.len += sizeof(uint8_t);
        break;
        case 16:{
            short v = (short)std::stoi(value);
            CLogger::getInstance()->log_w("0================16 v = %d", v);
            bswap_16((uint8_t*)&v);
            CLogger::getInstance()->log_w("1================16 v = %d", v);
            *(short *)(data.data+data.len) = v;
            data.len += sizeof(short);
        }
        break;
        case 18:{
            uint16_t v = (uint16_t)std::stoi(value);
            CLogger::getInstance()->log_w("0================18 v = %d", v);
            bswap_16((uint8_t*)&v);
            CLogger::getInstance()->log_w("1================18 v = %d", v);
            *(uint16_t *)(data.data+data.len) = v;
            data.len += sizeof(uint16_t);
        }
        break;
        case 5:{
            int v = (int)std::stoi(value);
            // uint16_t* p = (uint16_t *)&v;
            // wswap_32(p);
            // bswap_16((uint8_t*)p);
            // bswap_16((uint8_t*)p+1);
            // *(int *)(data.data+data.len) = v;
            uint8_t* pv = (uint8_t*)&v;
            *(data.data+data.len)   = pv[3];
            *(data.data+data.len+1) = pv[2];
            *(data.data+data.len+2) = pv[1];
            *(data.data+data.len+3) = pv[0];
            
            data.len += sizeof(int);
        }
        break;
        case 6:{
            // *(uint32_t *)(data.data+data.len) = (uint32_t)std::stoi(value);
            uint32_t v = (uint32_t)std::stoi(value);
            // uint16_t* p = (uint16_t *)&v;
            // wswap_32(p);
            // bswap_16((uint8_t*)p);
            // bswap_16((uint8_t*)p+1);
            // *(uint32_t *)(data.data+data.len) = v;
            uint8_t* pv = (uint8_t*)&v;
            *(data.data+data.len)   = pv[3];
            *(data.data+data.len+1) = pv[2];
            *(data.data+data.len+2) = pv[1];
            *(data.data+data.len+3) = pv[0];
            data.len += sizeof(uint32_t);
        }
        break;
        // case DLT698_DATA_TYPE_LONG:
        //     *(long *)(data.data+data.len) = (long)std::stol(value);
        //     data.len += sizeof(long);
        // break;
        // case DLT698_DATA_TYPE_ULONG:
        //     *(unsigned long *)(data.data+data.len) = (unsigned long)std::stoul(value);
        //     data.len += sizeof(unsigned long);
        // break;
        case 20:{
            int64_t v = (int64_t)std::stoll(value);
            int8_t* pv = (int8_t*)&v;
            for(int i = 0; i < sizeof(int64_t); i++){
                *(data.data+data.len+i)   = pv[sizeof(int64_t)-i-1];
            }
            // *(int64_t *)(data.data+data.len) = (int64_t)std::stoll(value);
            data.len += sizeof(int64_t);
        }
        break;
        case 21:{
            // *(uint64_t *)(data.data+data.len) = (uint64_t)std::stoull(value);
            uint64_t v = (int64_t)std::stoll(value);
            int8_t* pv = (int8_t*)&v;
            for(int i = 0; i < sizeof(uint64_t); i++){
                *(data.data+data.len+i)   = pv[sizeof(uint64_t)-i-1];
            }
            data.len += sizeof(uint64_t);
        }
        break;
        case 23:
            *(float *)(data.data+data.len) = (float)std::stof(value);
            data.len += sizeof(float);
        break;
        case 24:
            *(double *)(data.data+data.len) = (double)std::stod(value);
            data.len += sizeof(double);
        break;
        case 9:
        case 10:
        case 12:
            memcpy(data.data+data.len, value.c_str(), value.length());
            data.len += value.length();
        break;
        default:
        break;
    }
    return 0;
}
//
int GETRequest::get_oad_data(DLT698_BUFFER& data, std::string oad){
    std::list<MAPPING_POINT_DATA_TYPE> mapping_datas;
    MappingDataManager::getInstance().get_value_by_oad(mapping_datas, oad);
    if(mapping_datas.empty()){
        data.data[data.len] = 0;  //1-data;0-DAR
        data.len += 1;
        return data.len;
    }
    data.data[data.len] = 1;  //1-data;0-DAR
    data.len += 1;

    if(1 < mapping_datas.size()){
        data.data[data.len] =0x01;
        data.len += 1;
        data.data[data.len] = mapping_datas.size();
        data.len += 1;
    }
    for(auto mapping_data = mapping_datas.begin(); mapping_data != mapping_datas.end(); mapping_data++){
        int data_type = get_base_data_type(*mapping_data);
        data.data[data.len] = data_type;
        data.len += 1;
        fill_data(data_type, data, mapping_data->value);
    }
    return data.len;
}
int GETRequest::get_request_normal(DLT698_FRAME& frame, CONNECT_REQUEST_FRAME& params, DLT698_BUFFER& data){
    data.data[data.len] = frame.apdu.piid.value;
    data.len += sizeof(frame.apdu.piid.value);
    OAD oad;
    memcpy(oad.value, (frame.apdu.apdu+3), sizeof(oad.value));
    memcpy(data.data+data.len, oad.value, sizeof(oad.value));
    data.len += sizeof(oad.value);

    char oad_str[16] = {0};
    snprintf(oad_str, sizeof(oad_str), "%02X%02X%02X%02X", oad.value[0], oad.value[1], oad.value[2], oad.value[3]);
    CLogger::getInstance()->log_i("OAD: %s", oad_str);

    get_oad_data(data, oad_str);
    data.data[data.len] = 0;
    data.len += 1;
    data.data[data.len] = 0;
    data.len += 1;
    data.segment = 0;
    return data.len;
}

int GETRequest::get_request_normal_list(DLT698_FRAME& frame, CONNECT_REQUEST_FRAME& params, DLT698_BUFFER& data){
    // int offset = data.len;
    data.data[data.len] = frame.apdu.piid.value;
    data.len += sizeof(frame.apdu.piid.value);
    int count = frame.apdu.apdu[3];
    data.data[data.len] = count;
    data.len += 1;
    for(int i = 0; i < count; i++){
        OAD oad;
        memcpy(oad.value, (frame.apdu.apdu+4+i*sizeof(oad.value)), sizeof(oad.value));
        memcpy(data.data+data.len, oad.value, sizeof(oad.value));
        data.len += sizeof(oad.value);
        char oad_str[16] = {0};
        snprintf(oad_str, sizeof(oad_str), "%02X%02X%02X%02X", oad.value[0], oad.value[1], oad.value[2], oad.value[3]);
        CLogger::getInstance()->log_i("get request normal list OAD: %s", oad_str);
        // printf("get_request_normal_list  OAD: %02X%02X%02X%02X\n", oad.value[0], oad.value[1], oad.value[2], oad.value[3]);
        get_oad_data(data, oad_str);
    }
    data.data[data.len] = 0;
    data.len += 1;
    data.data[data.len] = 0;
    data.len += 1;
    data.segment = 0;
    return data.len;
}
uint8_t GETRequest::get_apdu_func_resp_tag(uint8_t tag){
    uint8_t func_tag = tag;
    switch (tag){
        case GET_REQUEST_NORMAL:
            func_tag = GET_RESPONSE_NORMAL;
            break;
        case GET_REQUEST_NORMAL_LIST:
            func_tag = GET_RESPONSE_NORMAL_LIST;
            break;
        case GET_REQUEST_NEXT:
            func_tag = GET_RESPONSE_NEXT;
            break;
        case GET_REQUEST_RECORD:
            func_tag = GET_RESPONSE_RECORD;
            break;
        case GET_REQUEST_RECORD_LIST:
            func_tag = GET_RESPONSE_RECORD_LIST;
            break;
        case GET_REQUEST_MD5:
            func_tag = GET_RESPONSE_MD5;
            break;
        default:
            break;
    }
    return func_tag;
}

int GETRequest::handle(DLT698_FRAME& frame, CONNECT_REQUEST_FRAME& params, DLT698_BUFFER& data){
    int ret = -1;
    data.data[data.len] = get_apdu_func_resp_tag(frame.apdu.func_tag);
    data.len += 1;
    printf("func_tag =%02X   resp_func_tag = %02X\n", frame.apdu.func_tag, data.data[1]);
    switch(frame.apdu.func_tag){
        case GET_REQUEST_NORMAL:
            ret = get_request_normal(frame, params, data);
            break;
        case GET_REQUEST_NORMAL_LIST:
            ret = get_request_normal_list(frame, params, data);
            break;
        case GET_REQUEST_NEXT:
            break;
        case GET_REQUEST_RECORD:
            break;
        case GET_REQUEST_RECORD_LIST:
            break;
        case GET_REQUEST_MD5:
            break;
    }
}